package libs;

import java.util.Iterator;
import java.util.Vector;

public class Normalization {

    /**
     *
     * @param vect
     * @return It's a pretty simple concept. Suppose that a teacher wants to
     * rank her students on a scale of 1-10. She uses their average test score
     * percentages to rank them.
     *
     * If the best average score is 95, and the worst is 23, then she wants a
     * normalization function f(x) such that
     *
     * f(minimum average test score) = minimum rank f(maximum average test
     * score) = maximum rank
     *
     * So if her normalization function is linear, then she can write it as
     *
     * f(x) = Ax + B
     *
     * We can solve for A and B by using the two known values:
     *
     * A * (minimum score) + B = minimum rank A * (maximum score) + B = maximum
     * rank
     *
     * So A = (maximum rank - minimum rank)/(maximum score - minimum score) and
     * B = minimum rank - A * (minimum score)
     *
     * For the example above, A = (10-1)/(95-23) = 0.125. B = 1 - 0.125 * 23 =
     * -1.875
     *
     * So the students who score 95 will have rank 10, and those who score 23
     * will have rank 1, and those who score in the middle, say 50, will have
     * rank:
     *
     * 0.125*50 - 1.875 = 4.375
     *
     * Min-max normalisation just means linearly mapping your data so that the
     * max and min of your input data are mapped to the predefined min and max
     * of your desired scale.
     *
     * Other kinds of normalization map the input data to achieve a predefined
     * mean and standard deviation, instead of a predefined minimum and maximum.
     * Normalization in general just means mapping your data into some more
     * standard form.
     *
     * Xnew=(X-Xmin)/(Xmax-Xmin)
     */
    public Vector getMinMax(Vector vect) {

        Vector v = new Vector();
        double max = getMax(vect);
        double min = getMin(vect);
        if (min == 0.1) {
            println("max:" + max);
            println("min:" + min);

        }
        for (int i = 0; i < vect.size(); i++) {
            double n = Double.parseDouble(vect.get(i).toString());
            if ((max - min) == 0) {
                v.add(0.0);
                continue;
            }
            double x = Utils.formatDouble((n - min) / (max - min));

            v.add(x);
        }
        return v;
    }

    public String[][] normalizeDataSetMinMax(String[][] data) {
        String[][] ret = new String[data.length][data[0].length];
        //ret=transposeMatrix(data);
        Vector v1 = new Vector();
        for (int i = 0; i < data[0].length; i++) {
            v1.removeAllElements();
            for (int j = 0; j < data.length; j++) {
                v1.add(data[j][i]);
            }
            //println("v1 length:"+v1.size());
            v1 = getMinMax(v1);
            for (int j = 0; j < ret.length; j++) {
                ret[j][i] = v1.get(j).toString();
            }
        }
        return ret;
    }

    public String[][] normalizeDataSetZScore(String[][] prm) {
        // yanlislikla rowlari normalize etmisiz gercekte columnlari normalize etmek gerekiyor
        //		for (int i = 0; i < prm.length; i++) {
        //			Vector ret = getVector(prm[i]);			
        //			moments mom = new moments();
        //			double mean = mom.findMean(ret);
        //			double std_dev = mom.findStdDeviation(ret);
        //			double d;
        //			for (int j = 0; j < ret.size(); j++) {
        //				d = ((Double) ret.get(j) - mean) / std_dev;
        //				d=formatDouble(d);
        //				//println(d+"");
        //				retDizi[i][j]=d+"";
        //			}
        //			//retDizi[i][ret.size()-1]=prm[i][ret.size()-1];
        //		}

        String[][] retDizi = new String[prm.length][prm[0].length];
        try {
            for (int j = 0; j < prm[0].length; j++) {
                String[] st = new String[prm.length];
                for (int i = 0; i < prm.length; i++) {
                    st[i] = prm[i][j];
                }
                Vector<String> ret = getVector(st);
                Moments mom = new Moments();
                double mean = mom.findMean(ret);
                double std_dev = mom.findStdDeviation(ret);
                double d;
                for (int k = 0; k < ret.size(); k++) {
                    if (std_dev == 0.0) {
                        retDizi[k][j] = "0.0";
                    } else {
                        d = (Double.parseDouble(ret.get(k)) - mean) / std_dev;
                        
                        d = Utils.formatDouble(d);
                        retDizi[k][j] = d + "";
                    }
                }
            }

        } catch (Exception e) {
           println("hata oldu");
           e.printStackTrace();
        }
        return retDizi;
    }

    public String[][] normalizeDataSetUnitVector(String[][] prm) {
        String[][] retDizi = new String[prm.length][prm[0].length];
        for (int j = 0; j < prm[0].length; j++) {
            String[] st = new String[prm.length];
            for (int i = 0; i < prm.length; i++) {
                st[i] = prm[i][j];
            }
            Vector<String> ret = getVector(st);
            Moments mom = new Moments();
            double magnitude = mom.findMagnitude(ret);
            double d;
            for (int k = 0; k < ret.size(); k++) {
                d = Double.parseDouble(ret.get(k)) / magnitude;
                d = Utils.formatDouble(d);
                //println(d+"");
                retDizi[k][j] = d + "";
            }

        }
        return retDizi;
    }

    public String[][] normalizeDataSetTanH(String[][] prm) {

        String[][] retDizi = new String[prm.length][prm[0].length];
        for (int j = 0; j < prm[0].length; j++) {
            String[] st = new String[prm.length];
            for (int i = 0; i < prm.length; i++) {
                st[i] = prm[i][j];
            }
            Vector<String> ret = getVector(st);
            Moments mom = new Moments();
            double mean = mom.findMean(ret);
            double std_dev = mom.findStdDeviation(ret);
            double d;
            for (int k = 0; k < ret.size(); k++) {
                d = 0.5 * (Math.tanh(0.01 * ((Double.parseDouble(ret.get(k)) - mean) / std_dev)) + 1);
                d = Utils.formatDouble(d);
                //println(d+"");
                retDizi[k][j] = d + "";
            }

        }
        return retDizi;
    }

    private void println(String msg) {
        // TODO Auto-generated method stub
        System.out.println(msg);
    }

    private Vector<String> getVector(String[] prm) {
        try {
            Vector<String> ret = new Vector<String>();
            for (int i = 0; i < prm.length; i++) {
//          ret.add(getDouble(prm[i]+""));
                ret.add(prm[i]);
            }
            return ret;
        } catch (Exception e) {
            println("yine hata");
        }
        return null;
    }

    public int getInt(String param) {
        return Integer.parseInt(param);
    }

    public float getFloat(String param) {
        return Float.parseFloat(param);
    }

    public double getDouble(String param) {
        try {
            return Double.parseDouble(param);
        } catch (Exception e) {
            //yaz("gelen param:"+param);
            return 0;
        }

    }

    public String[][] transposeMatrix(String[][] data) {
        String[][] ret = new String[data[0].length][data.length];
        for (int i = 0; i < data[0].length; i++) {
            for (int j = 0; j < data.length; j++) {
                ret[i][j] = data[j][i];
            }
        }
        return ret;
    }

    public double getMin(Vector data) {

        Object[] dizi = data.toArray();
        double min = Double.parseDouble(dizi[0].toString());
        for (int i = 0; i < dizi.length; i++) {
            double n = Double.parseDouble(dizi[i].toString());
            if (n < min) {
                min = n;
            }
        }
        return min;
        //Object obj=Collections.min(data);
        //return Double.parseDouble(obj.toString());
    }

    public double getMax(Vector data) {
        Object[] dizi = data.toArray();
        double max = Double.parseDouble(dizi[0].toString());
        for (int i = 0; i < dizi.length; i++) {
            double n = Double.parseDouble(dizi[i].toString());
            if (n > max) {
                max = n;
            }
        }
        return max;
        //Object obj=Collections.max(data);
        //return Double.parseDouble(obj.toString());
    }

    public double getMean(Vector data) {
        double toplam = 0.0;
        for (Iterator iter = data.iterator(); iter.hasNext();) {
            double element = Double.parseDouble(iter.next().toString());
            toplam += element;
        }
        double ret = toplam / data.size();
        return ret;
    }

    public String[][] normalizeDataSetForLastColumn(String[][] data, String[][] data2) {
        Vector v1 = new Vector();
        for (int j = 0; j < data2.length; j++) {
            v1.add(data2[j][data2[0].length - 1]);
        }
        v1 = getMinMax(v1);
        for (int i = 0; i < data.length; i++) {
            data[i][data[0].length - 1] = v1.get(i).toString();
        }
        return data;
    }

    public String[][] normalizeDataSetBySigmoidFunctionForLastColumn(String[][] data) {
        Vector v1 = new Vector();
        for (int j = 0; j < data.length; j++) {
            v1.add(data[j][data[0].length - 1]);
        }

        v1 = getSigmoidalNormalization(v1);
//		v1=getMinMaxNormalization(v1);
        for (int i = 0; i < data.length; i++) {
            data[i][data[0].length - 1] = v1.get(i).toString();
        }
        return data;
    }

    public String[][] normalizeDataSetSigmoidal(String[][] prm) {
        String[][] retDizi = new String[prm.length][prm[0].length];
        for (int j = 0; j < prm[0].length; j++) {
            String[] st = new String[prm.length];
            for (int i = 0; i < prm.length; i++) {
                st[i] = prm[i][j];
            }
            double d;
            for (int k = 0; k < st.length; k++) {
                d = 1.0 / (1 + Math.exp(-Double.parseDouble(st[k])));
                d = Utils.formatDouble(d);
                retDizi[k][j] = d + "";
            }
        }
        return retDizi;
    }

    private Vector getSigmoidalNormalization(Vector v) {
        Vector v1 = new Vector();
        for (int i = 0; i < v.size(); i++) {
            double y = 1.0 / (1 + Math.exp(-Double.parseDouble(v.get(i).toString())));
            y = Utils.formatDouble(y);
            v1.add(y);
        }

        return v1;
    }

    private Vector getMinMaxNormalization(Vector v) {
        Vector v1 = new Vector();
        double min = getMin(v);
        double max = getMax(v);
        for (int i = 0; i < v.size(); i++) {
            double x = Double.parseDouble(v.get(i).toString());
            double y = (x - min) / (max - min);
            y = Utils.formatDouble(y);
            v1.add(y);
        }

        return v1;
    }
}
